package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.github.xiaoymin.knife4j.core.util.CollectionUtils;
import com.zzyl.base.ResponseResult;
import com.zzyl.constant.AccraditationRecordConstant;
import com.zzyl.constant.RetreatConstant;
import com.zzyl.dto.CheckInDto;
import com.zzyl.dto.ElderDto;
import com.zzyl.entity.CheckIn;
import com.zzyl.entity.Dept;
import com.zzyl.entity.Elder;
import com.zzyl.entity.User;
import com.zzyl.mapper.CheckInMapper;
import com.zzyl.mapper.DeptMapper;
import com.zzyl.mapper.UserMapper;
import com.zzyl.service.AccraditationRecordService;
import com.zzyl.service.CheckInService;
import com.zzyl.service.ElderService;
import com.zzyl.utils.CodeUtil;
import com.zzyl.utils.UserThreadLocal;
import com.zzyl.vo.RecordVo;
import com.zzyl.vo.retreat.ElderVo;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author sjqn
 */
@Service
public class CheckInServiceImpl implements CheckInService {
    @Autowired
    private AccraditationRecordService accraditationRecordService;

    @Autowired
    private ElderService elderService;

    @Autowired
    private CheckInMapper checkInMapper;

    private static final String CHECK_IN_CODE_PREFIX = "RZ";

    @Autowired
    private RedisTemplate<String,String> redisTemplate;


    /**
     * 创建入住申请
     * @param checkInDto
     * @return
     */
    @Override
    public ResponseResult createCheckIn(CheckInDto checkInDto) {

        //1.验证状态，如果老人已经发起申请，则不能再次发起
        ElderVo elderVo = elderService.selectByIdCardAndName(checkInDto.getElderDto().getIdCardNo(), checkInDto.getElderDto().getName());
        if(null != elderVo && checkInDto.getId() == null && !elderVo.getStatus().equals(5)){
            return ResponseResult.error(checkInDto.getElderDto().getName()+"已经发起了申请入住");
        }

        //2.保存老人信息
        ElderDto elderDto = checkInDto.getElderDto();
        String otherApplyInfo = checkInDto.getOtherApplyInfo();
        JSONObject jsonObject = JSONUtil.toBean(otherApplyInfo, JSONObject.class);
        elderDto.setAge(jsonObject.get("age").toString());
        elderDto.setSex(jsonObject.get("sex").toString());
        elderDto.setImage(checkInDto.getUrl1());
        Elder elder = elderService.insert(elderDto);

        //3.保存入住信息
        CheckIn checkIn = BeanUtil.toBean(checkInDto, CheckIn.class);
        //入住申请的所有信息
        checkIn.setOtherApplyInfo(JSONUtil.toJsonStr(checkInDto));
        //编码
        String checkInCode = CodeUtil.generateCode(CHECK_IN_CODE_PREFIX, redisTemplate, 5);
        checkIn.setCheckInCode(checkInCode);
        //标题
        checkIn.setTitle(elder.getName()+"的入住申请");
        //老人id
        checkIn.setElderId(elder.getId());

        //获取线程中的用户信息
        String subject = UserThreadLocal.getSubject();
        User user = JSONUtil.toBean(subject, User.class);

        //养老顾问，申请人
        checkIn.setCounselor(user.getRealName());
        checkIn.setApplicat(user.getRealName());

        // 申请人id
        checkIn.setApplicatId(user.getId());

        // 申请人部门编号
        checkIn.setDeptNo(user.getDeptNo());

        //流程状态
        checkIn.setFlowStatus(CheckIn.FlowStatus.APPLY.getCode());

        //审核状态
        checkIn.setStatus(CheckIn.Status.APPLICATION.getCode());

        //其他信息
        checkIn.setOtherApplyInfo(JSONUtil.toJsonStr(checkInDto));

        checkInMapper.insert(checkIn);

        //4.准备流程变量
        Map<String, Object> variables = setVariables(checkIn);

        //5.启用流程实例，并且自动完成首页点
        // 业务相关，登录用户相关。processDefinitionkey（checkIn-new）
        start(checkIn.getId(),"checkIn",user,variables,true);

        //6.保存审核记录
        Long nextAssignee = getNextAssignee("checkIn","checkIn:"+checkIn.getId());
        RecordVo recordVo = getRecordVo(
                checkIn,user, AccraditationRecordConstant.AUDIT_STATUS_PASS,
                "同意","发起申请-申请入住","护理组组长处理-入住评估",nextAssignee,
                AccraditationRecordConstant.RECORD_HANDLE_TYPE_PROCESSED
        );
        accraditationRecordService.insert(recordVo);
        return ResponseResult.success();
    }
    @Autowired
    private TaskService taskService;

    /**
     * 启动流程实例，如果当前登录人是第一个节点的执行人，则自动执行任务
     * @param id  业务id
     * @param processDefinitionKey  流程定义key
     * @param user    当前登录用户
     * @param variables  流程变量参数
     * @param autoFinished   是否自动完成
     */
    private void start(Long id, String processDefinitionKey, User user, Map<String, Object> variables, boolean autoFinished) {

        String businessKey = processDefinitionKey + ":" + id;
        //启动流程实例
        startProcess(processDefinitionKey,variables,businessKey);

        //用户登录，防止报错
        Authentication.setAuthenticatedUserId(user.getId().toString());
        //查询任务
        List<Task> list = taskService.createTaskQuery()
                .processDefinitionKey(processDefinitionKey)
                .taskAssignee(user.getId().toString())
                .list();
        //必须首节点
        list = list.stream().filter(t->"0".equals(t.getFormKey())).collect(Collectors.toList());

        if(!CollectionUtils.isEmpty(list) && autoFinished){
            for (Task task : list) {
                Map<String, Object> variables2 = new HashMap<>();
                variables2.put("processStatus",1);
                variables2.put("ops",1);

                taskService.complete(task.getId(),variables2);
            }
        }

    }

    @Autowired
    private RuntimeService runtimeService;

    /**
     * 启动流程实例
     * @param processDefinitionKey
     * @param variables
     * @param businessKey
     */
    private ProcessInstance startProcess(String processDefinitionKey, Map<String, Object> variables, String businessKey) {
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variables);
        return processInstance;
    }

    /**
     * 封装审核记录参数
     * @param checkIn  入住对象
     * @param user  当前登录用户
     * @param status  审核状态
     * @param option  操作意见
     * @param step  当前步骤
     * @param nextSetp  下一步操作人
     * @param nextAssignee  下一个审核人
     * @param handleType  处理类型（0:已审批，1：已处理）
     * @return
     */
    private RecordVo getRecordVo(CheckIn checkIn, User user, Integer status, String option, String step, String nextSetp, Long nextAssignee, Integer handleType) {

        RecordVo recordVo = new RecordVo();
        recordVo.setId(checkIn.getId());
        recordVo.setType(AccraditationRecordConstant.RECORD_TYPE_CHECK_IN);
        recordVo.setFlowStatus(checkIn.getFlowStatus());
        recordVo.setHandleType(handleType);
        recordVo.setStatus(status);
        recordVo.setOption(option);
        recordVo.setNextStep(nextSetp);
        recordVo.setNextAssignee(nextAssignee);
        recordVo.setUserId(user.getId());
        recordVo.setStep(step);
        recordVo.setRealName(user.getRealName());

        return recordVo;
    }


    /**
     * 获取下一个审核人
     * @param processDifinitionKey
     * @param bussinessKey
     * @return
     */
    private Long getNextAssignee(String processDifinitionKey, String bussinessKey) {

        Task task = taskService.createTaskQuery().processDefinitionKey(processDifinitionKey).processInstanceBusinessKey(bussinessKey).singleResult();
        if(task != null){
            return Long.valueOf(task.getAssignee());
        }
        return null;
    }

    @Autowired
    private DeptMapper deptMapper;

    @Autowired
    private UserMapper userMapper;

    /**
     * 准备流程变量
     * @param checkIn
     * @return
     */
    private Map<String, Object> setVariables(CheckIn checkIn) {
        //设置流程变量
        Map<String, Object> variables = new HashMap<>();
        //养老顾问
        variables.put("assignee0",checkIn.getApplicatId());
        //入住单的其他信息
        variables.put("assignee0Name",checkIn.getApplicat());
        variables.put("processTitle",checkIn.getTitle());

        //护理主管
        Dept dept = deptMapper.selectByDeptNo(RetreatConstant.NURSING_DEPT_CODE);
        variables.put("assignee1",dept.getLeaderId());
        //院长
        List<Long> useridList = userMapper.selectByDeptNo(RetreatConstant.DEAN_OFFICE_DEPT_CODE);
        variables.put("assignee2",useridList.get(0));

        //养老顾问
        variables.put("assignee3",checkIn.getApplicatId());

        //法务员工
        List<Long> legatUserIdList = userMapper.selectByDeptNo(RetreatConstant.DEAN_OFFICE_DEPT_CODE);
        variables.put("assignee4",legatUserIdList.get(legatUserIdList.size() - 1));

        //设置流程类型   入住
        variables.put("processType",3);

        //流程类型code
        variables.put("processCode",checkIn.getCheckInCode());

        //流程类型 状态
        variables.put("processStatus",1);

        return variables;
    }
}